
;                                                                                                                              Nov 2012
; fancy disassembler engine (fde32)
;

  ; structure representing any instruction

struct fde32s
  len	      rb 1
  prefix      rb 1
  prefix.lock rb 1
  prefix.rep  rb 1
  prefix.seg  rb 1
  prefix.66   rb 1
  prefix.67   rb 1
  vex	      rb 1
  vex2	      rb 1
  vex3	      rb 1
  vex.r       rb 1
  vex.x       rb 1
  vex.b       rb 1
  vex.m_mmmm  rb 1
  vex.w       rb 1
  vex.vvvv    rb 1
  vex.l       rb 1
  vex.pp      rb 1
  opcode.len  rb 1
  opcode      rb 1
  opcode2     rb 1
  opcode3     rb 1
  modrm       rb 1
  modrm.mod   rb 1
  modrm.reg   rb 1
  modrm.rm    rb 1
  sib	      rb 1
  sib.scale   rb 1
  sib.index   rb 1
  sib.base    rb 1
  union
    disp8     rb 1
    disp16    rw 1
    disp32    rd 1
  ends
  union
    imm8      rb 1
    imm16     rw 1
    imm32     rd 1
  ends
  union
    imm8_2    rb 1
    imm16_2   rw 1
  ends
  flags       rd 1
ends

  ; flags

  F_NONE	      = 00000000h
  F_MODRM	      = 00000001h
  F_SIB 	      = 00000002h
  F_DISP8	      = 00000004h
  F_DISP16	      = 00000008h
  F_DISP32	      = 00000010h
  F_DISP	      = F_DISP8+F_DISP16+F_DISP32
  F_IMM8	      = 00000020h
  F_IMM16	      = 00000040h
  F_IMM32	      = 00000080h
  F_IMM 	      = F_IMM8+F_IMM16+F_IMM32
  F_RELATIVE	      = 00000100h
  F_GROUP	      = 00000200h	; index specified in modrm.reg
  F_VEX_BAD_PREFIX    = 00000400h
  F_ERROR_LOCK	      = 00000800h	; lock-prefix not possible
  F_ERROR_LENGTH      = 00001000h
  F_ERROR_OPCODE      = 00002000h	; undefined opcode

  ; prefix flags

  PRE_NONE	      = 000h
  PRE_LOCK	      = 001h
  PRE_REP	      = 002h
  PRE_SEG	      = 004h
  PRE_66	      = 008h
  PRE_67	      = 010h
  PRE_VEX	      = 020h		; partly encoded in complements to distinguish from les/lds
  PRE_ALL	      = PRE_LOCK+PRE_REP+PRE_SEG+PRE_66+PRE_67
  PRE_ALL32	      = PRE_ALL+PRE_VEX

  ; vex-prefix m-mmmm

  M_MMMM_0F	      = 1
  M_MMMM_0F_38	      = 2
  M_MMMM_0F_3A	      = 3

  ; vex-prefix l

  L_SCALAR	      = 0
  L_128_VECTOR	      = 0
  L_256_VECTOR	      = 1

  ; vex-prefix pp

  PP_NONE	      = 0
  PP_66 	      = 1
  PP_F3 	      = 2
  PP_F2 	      = 3

  ; modr/m mod

  MOD_NODISP	      = 0
  MOD_DISP8	      = 1
  MOD_DISP16	      = 2
  MOD_DISP32	      = 2
  MOD_REG	      = 3

  ; modr/m reg

  ; GPRs
  REG_EAX	      = 0
  REG_ECX	      = 1
  REG_EDX	      = 2
  REG_EBX	      = 3
  REG_ESP	      = 4
  REG_EBP	      = 5
  REG_ESI	      = 6
  REG_EDI	      = 7
  REG_AL	      = REG_EAX
  REG_AH	      = REG_ESP
  REG_CL	      = REG_ECX
  REG_CH	      = REG_EBP
  REG_DL	      = REG_EDX
  REG_DH	      = REG_ESI
  REG_BL	      = REG_EBX
  REG_BH	      = REG_EDI
  ; special
  REG_DR0	      = REG_EAX
  REG_DR1	      = REG_ECX
  REG_DR2	      = REG_EDX
  REG_DR3	      = REG_EBX
  REG_DR4	      = REG_ESP 	; refers to DR6 if CR4.DE is cleared
  REG_DR5	      = REG_EBP 	; refers to DR7 ^
  REG_DR6	      = REG_ESI
  REG_DR7	      = REG_EDI
  REG_CR0	      = REG_EAX
  REG_CR2	      = REG_EDX
  REG_CR3	      = REG_EBX
  REG_CR4	      = REG_ESP
  ; MMX/XMM/YMM
  REG_SIMD0	      = REG_EAX
  REG_SIMD1	      = REG_ECX
  REG_SIMD2	      = REG_EDX
  REG_SIMD3	      = REG_EBX
  REG_SIMD4	      = REG_ESP
  REG_SIMD5	      = REG_EBP
  REG_SIMD6	      = REG_ESI
  REG_SIMD7	      = REG_EDI
  ; FPU
  REG_ST0	      = REG_EAX
  REG_ST1	      = REG_ECX
  REG_ST2	      = REG_EDX
  REG_ST3	      = REG_EBX
  REG_ST4	      = REG_ESP
  REG_ST5	      = REG_EBP
  REG_ST6	      = REG_ESI
  REG_ST7	      = REG_EDI
  ; Sregs
  SEG_ES	      = REG_EAX
  SEG_CS	      = REG_ECX
  SEG_SS	      = REG_EDX
  SEG_DS	      = REG_EBX
  SEG_FS	      = REG_ESP
  SEG_GS	      = REG_EBP

  ; modr/m r/m

  RM_SIB	      = REG_ESP
  RM_DISP16	      = REG_ESI
  RM_DISP32	      = REG_EBP

  ; sib scale

  SCALE_1	      = 0
  SCALE_2	      = 1
  SCALE_4	      = 2
  SCALE_8	      = 3

  ; prefixes

  PREFIX_SEGMENT_CS   = 02Eh
  PREFIX_SEGMENT_SS   = 036h
  PREFIX_SEGMENT_DS   = 03Eh
  PREFIX_SEGMENT_ES   = 026h
  PREFIX_SEGMENT_FS   = 064h
  PREFIX_SEGMENT_GS   = 065h
  PREFIX_LOCK	      = 0F0h
  PREFIX_REPNZ	      = 0F2h
  PREFIX_REP	      = 0F3h
  PREFIX_OPERAND_SIZE = 066h
  PREFIX_ADDRESS_SIZE = 067h
  PREFIX_VEX_2_BYTE   = 0C5h
  PREFIX_VEX_3_BYTE   = 0C4h

  ; encoding routine

proc encode
    virtual at esi
	.in	fde32s
    end virtual
	pushad
	mov	edi,ecx
	mov	esi,edx
	push	ecx
	mov	cl,[.in.prefix]
	test	cl,PRE_SEG
	je	.no_seg
	mov	al,[.in.prefix.seg]
	stosb
    .no_seg:
	test	cl,PRE_67
	je	.no_67
	mov	al,PREFIX_ADDRESS_SIZE
	stosb
    .no_67:
	test	cl,PRE_VEX
	jnz	.wr_vex
	test	cl,PRE_LOCK
	je	.no_lock
	mov	al,PREFIX_LOCK
	stosb
    .no_lock:
	test	cl,PRE_REP
	je	.no_rep
	mov	al,[.in.prefix.rep]
	stosb
    .no_rep:
	test	cl,PRE_66
	je	.no_66
	mov	al,PREFIX_OPERAND_SIZE
	stosb
    .no_66:
	test	cl,PRE_VEX
	je	.no_vex
    .wr_vex:
	mov	al,[.in.vex]
	stosb
	mov	ah,al
	cmp	[.in.vex.r],-1
	jnz	.re_vex_2byte
	mov	al,[.in.vex2]
	stosb
	cmp	ah,PREFIX_VEX_3_BYTE
	jnz	.no_vex
	mov	al,[.in.vex3]
	stosb
	jmp	.no_vex
    .re_vex_2byte:
	cmp	ah,PREFIX_VEX_2_BYTE
	jnz	.re_vex_3byte
	mov	al,[.in.vex.r]
	mov	ah,[.in.vex.vvvv]
	mov	cl,[.in.vex.l]
	mov	ch,[.in.vex.pp]
	not	al
	not	ah
	shl	al,7
	shl	ah,3
	shl	cl,2
	or	al,ah
	or	cl,ch
	or	al,cl
	stosb
	mov	al,[.in.opcode2]
	jmp	.wr_opcode
    .re_vex_3byte:
	mov	ax,word [.in.vex.r]
	mov	cx,word [.in.vex.b]
	not	ax
	not	cl
	shl	al,7
	shl	ah,6
	shl	cl,5
	or	al,ah
	or	cl,ch
	or	al,cl
	stosb
	mov	ax,word [.in.vex.w]
	mov	cx,word [.in.vex.l]
	not	ah
	shl	al,7
	shl	ah,3
	shl	cl,2
	or	al,ah
	or	cl,ch
	or	al,cl
	stosb
	mov	ah,[.in.vex.m_mmmm]
	mov	al,[.in.opcode2]
	cmp	ah,M_MMMM_0F
	je	.wr_opcode
	mov	al,[.in.opcode3]
	jmp	.wr_opcode
    .no_vex:
	mov	al,[.in.opcode]
    .wr_opcode:
	stosb
	test	[.in.prefix],PRE_VEX
	jnz	.opcode_ok
	cmp	al,0Fh
	jnz	.opcode_ok
	mov	al,[.in.opcode2]
	stosb
	cmp	al,38h
	je	.3_byte
	cmp	al,3Ah
	jnz	.opcode_ok
    .3_byte:
	mov	al,[.in.opcode3]
	stosb
    .opcode_ok:
	mov	ecx,[.in.flags]
	test	ecx,F_MODRM
	je	.no_modrm
	cmp	[.in.modrm.mod],-1
	jnz	.re_modrm
	mov	al,[.in.modrm]
	stosb
	jmp	.no_modrm
    .re_modrm:
	mov	ax,word [.in.modrm.mod]
	mov	dl,[.in.modrm.rm]
	shl	al,6
	shl	ah,3
	or	al,ah
	or	al,dl
	stosb
    .no_modrm:
	test	ecx,F_SIB
	je	.no_sib
	cmp	[.in.sib.scale],-1
	jnz	.re_sib
	mov	al,[.in.sib]
	stosb
	jmp	.no_sib
    .re_sib:
	mov	ax,word [.in.sib.scale]
	mov	dl,[.in.sib.base]
	shl	al,6
	shl	ah,3
	or	al,ah
	or	al,dl
	stosb
    .no_sib:
	test	ecx,F_DISP32
	je	.no_disp32
	mov	eax,[.in.disp32]
	stosd
	jmp	.no_disp8
    .no_disp32:
	test	ecx,F_DISP16
	je	.no_disp16
	mov	ax,[.in.disp16]
	stosw
	jmp	.no_disp8
    .no_disp16:
	test	ecx,F_DISP8
	je	.no_disp8
	mov	al,[.in.disp8]
	stosb
    .no_disp8:
	test	ecx,F_IMM32
	je	.no_imm32
	mov	eax,[.in.imm32]
	stosd
    .no_imm32:
	test	ecx,F_IMM16
	je	.no_imm16
	mov	ax,[.in.imm16]
	stosw
    .no_imm16:
	test	ecx,F_IMM8
	je	.no_imm8
	mov	al,[.in.imm8]
	stosb
    .no_imm8:
	pop	eax
	xchg	eax,edi
	sub	eax,edi
	mov	[.in.len],al
	mov	[esp+1Ch],eax
	popad
	retn
endp

  ; decoding routine

proc decode
    virtual at edx
	.out	fde32s
    end virtual
    virtual at ebp-.geip
	.base:
    end virtual
	pushad
	mov	esi,ecx
	push	ecx
	call	.geip
    .geip:
	pop	ebp
	xor	ecx,ecx
	xor	al,al
	mov	edi,edx
	mov	cl,sizeof.fde32s
	rep	stosb
    .prefix:
	lodsb
	mov	cl,al
	mov	ch,al
	and	cl,0FEh
	and	ch,0E7h
	cmp	al,PREFIX_LOCK
	je	.lock
	cmp	cl,PREFIX_REPNZ
	je	.rep
	cmp	al,PREFIX_OPERAND_SIZE
	je	.66
	cmp	al,PREFIX_ADDRESS_SIZE
	je	.67
	cmp	cl,PREFIX_SEGMENT_FS
	je	.seg
	cmp	ch,PREFIX_SEGMENT_CS
	jnz	.vex
      .seg:
	or	[.out.prefix],PRE_SEG
	mov	[.out.prefix.seg],al
	jmp	.prefix
      .lock:
	or	[.out.prefix],PRE_LOCK
	mov	[.out.prefix.lock],al
	jmp	.prefix
      .rep:
	or	[.out.prefix],PRE_REP
	mov	[.out.prefix.rep],al
	jmp	.prefix
      .66:
	or	[.out.prefix],PRE_66
	mov	[.out.prefix.66],al
	jmp	.prefix
      .67:
	or	[.out.prefix],PRE_67
	mov	[.out.prefix.67],al
	jmp	.prefix
    .vex:
	cmp	cl,PREFIX_VEX_3_BYTE
	jnz	.opcode
	mov	cl,al
	lodsb
	mov	ch,al
	and	ch,0C0h
	cmp	ch,0C0h
	je	.no_les_lds
	sub	esi,2
	lodsb
	jmp	.opcode
      .no_les_lds:
	mov	[.out.opcode],0Fh
	or	[.out.prefix],PRE_VEX
	mov	[.out.vex],cl
	mov	[.out.vex2],al
	test	[.out.prefix],PRE_LOCK+PRE_REP+PRE_66
	je	.vex_2_byte
	or	[.out.flags],F_VEX_BAD_PREFIX
      .vex_2_byte:
	cmp	cl,PREFIX_VEX_2_BYTE
	jnz	.vex_3_byte
	mov	ah,al
	mov	cl,al
	mov	ch,al
	shl	ah,1
	shl	cl,5
	shr	al,7
	shr	ah,4
	shr	cl,7
	and	ch,3
	or	al,0FEh
	or	ah,0F0h
	not	al
	not	ah
	mov	[.out.vex.r],al
	mov	[.out.vex.vvvv],ah
	mov	word [.out.vex.l],cx
	jmp	.vex_0F
      .vex_3_byte:
	mov	ah,al
	mov	cl,al
	mov	ch,al
	shl	ah,1
	shl	cl,2
	shr	al,7
	shr	ah,7
	shr	cl,7
	and	ch,01Fh
	or	al,0FEh
	or	ah,0FEh
	or	cl,0FEh
	not	al
	not	ah
	not	cl
	mov	word [.out.vex.r],ax
	mov	word [.out.vex.b],cx
	lodsb
	mov	[.out.vex3],al
	mov	ah,al
	mov	cl,al
	mov	bl,al
	shl	ah,1
	shl	cl,5
	shr	al,7
	shr	ah,4
	shr	cl,7
	and	bl,3
	or	ah,0F0h
	not	ah
	mov	word [.out.vex.w],ax
	mov	[.out.vex.l],cl
	mov	[.out.vex.pp],bl
	cmp	ch,M_MMMM_0F
	jnz	.vex_0F_38_3A
      .vex_0F:
	mov	bl,C_0F
	jmp	.2_byte
      .vex_0F_38_3A:
	mov	bl,C_3BYTE
	mov	bh,38h
	mov	[.out.opcode2],bh
	cmp	ch,M_MMMM_0F_38
	je	.3_byte
	mov	bh,3Ah
	mov	[.out.opcode2],bh
	jmp	.3_byte
    .opcode:
	mov	[.out.opcode.len],1
	mov	[.out.opcode],al
	lea	ebx,[.base+opcode_table]
      .next_opcode:
	mov	ah,al
      .loop:
	mov	cl,[ebx]
	mov	ch,[ebx]
	shr	cl,5
	and	ch,1Fh
	inc	cl
	inc	ebx
	sub	al,cl
	jnc	.loop
	mov	al,ch
	lea	ebx,[.base+flags_table]
	xlatb
	xchg	eax,ebx
	cmp	bl,C_UNDEFINED
	jnz	.2_byte
    .undefined:
	or	[.out.flags],F_ERROR_OPCODE
    .exit:
	xor	bl,bl
	jmp	.check_if_lock_is_valid
    .2_byte:
	cmp	bl,C_0F
	jnz	.3_byte
	lodsb
	mov	[.out.opcode.len],2
	mov	[.out.opcode2],al
	lea	ebx,[.base+opcode_table_0F]
	jmp	.next_opcode
    .3_byte:
	cmp	bl,C_3BYTE
	jnz	.moffs
	lodsb
	mov	[.out.opcode.len],3
	mov	[.out.opcode3],al
	xor	ecx,ecx
	mov	ah,sizeof.opcode_table_0F_38_V
	mov	cl,sizeof.opcode_table_0F_38
	test	[.out.prefix],PRE_VEX
	je	.skip_0F_38_V
	mov	cl,ah
      .skip_0F_38_V:
	lea	edi,[.base+opcode_table_0F_38]
	mov	bl,C_MODRM
	cmp	bh,38h
	je	.lookup
	mov	ah,sizeof.opcode_table_0F_3A_V
	mov	cl,sizeof.opcode_table_0F_3A
	test	[.out.prefix],PRE_VEX
	je	.skip_0F_3A_V
	mov	cl,ah
      .skip_0F_3A_V:
	lea	edi,[.base+opcode_table_0F_3A]
	mov	bl,C_MODRM+C_IMM8
      .lookup:
	repnz	scasb
	jnz	.undefined
	mov	bh,al
	jmp	.modrm
    .moffs:
	cmp	bl,C_MOFFS
	jnz	.modrm
	lea	edi,[.out.disp8]
	test	[.out.prefix],PRE_67
	je	.disp32
	or	[.out.flags],F_DISP16
	movsw
	jmp	.exit
      .disp32:
	or	[.out.flags],F_DISP32
	movsd
	jmp	.exit
    .modrm:
	test	bl,C_MODRM
	je	.imm
	lodsb
	or	[.out.flags],F_MODRM
	mov	[.out.modrm],al
	mov	cl,al
	mov	ch,al
	shl	ch,2
	shr	cl,6
	shr	ch,5
	and	al,7
	mov	word [.out.modrm.mod],cx
	mov	[.out.modrm.rm],al
	mov	ah,[.out.opcode]
	and	ah,0FEh
	cmp	ah,0F6h
	jnz	.no_F6_F7
	test	ch,ch
	je	.no_F6_F7
	and	bl,not (C_IMM8+C_IMM32)
      .no_F6_F7:
	test	[.out.prefix],PRE_67
	je	.modrm_32b
	cmp	cl,MOD_DISP16
	je	.modrm_16b_disp16
	cmp	cl,MOD_DISP8
	je	.modrm_16b_disp8
	test	cl,cl
	jnz	.disp
	cmp	al,RM_DISP16
	jnz	.disp
      .modrm_16b_disp16:
	or	[.out.flags],F_DISP16
	jmp	.disp
      .modrm_16b_disp8:
	or	[.out.flags],F_DISP8
	jmp	.disp
      .modrm_32b:
	cmp	cl,MOD_DISP32
	je	.modrm_32b_disp32
	cmp	cl,MOD_DISP8
	je	.modrm_32b_disp8
	test	cl,cl
	jnz	.sib
	cmp	al,RM_DISP32
	jnz	.sib
      .modrm_32b_disp32:
	or	[.out.flags],F_DISP32
	jmp	.sib
      .modrm_32b_disp8:
	or	[.out.flags],F_DISP8
    .sib:
	cmp	cl,MOD_REG
	je	.disp
	cmp	al,RM_SIB
	jnz	.disp
	lodsb
	or	[.out.flags],F_SIB
	mov	[.out.sib],al
	mov	ah,al
	mov	ch,al
	shl	ah,2
	shr	al,6
	shr	ah,5
	and	ch,7
	mov	word [.out.sib.scale],ax
	mov	[.out.sib.base],ch
	test	cl,cl
	jnz	.disp
	cmp	ch,REG_EBP
	jnz	.disp
	or	[.out.flags],F_DISP32
    .disp:
	lea	edi,[.out.disp8]
	test	[.out.flags],F_DISP32
	je	.disp16
	movsd
    .disp16:
	test	[.out.flags],F_DISP16
	je	.disp8
	movsw
    .disp8:
	test	[.out.flags],F_DISP8
	je	.imm
	movsb
    .imm:
	lea	edi,[.out.imm8]
	test	bl,C_IMM32
	je	.imm16
	test	[.out.prefix],PRE_66
	je	.imm32
	or	[.out.flags],F_IMM16
	movsw
	jmp	.got_either_32_or_16
      .imm32:
	or	[.out.flags],F_IMM32
	movsd
      .got_either_32_or_16:
	lea	edi,[.out.imm8_2]
    .imm16:
	test	bl,C_IMM16
	je	.imm8
	or	[.out.flags],F_IMM16
	movsw
	lea	edi,[.out.imm8_2]
    .imm8:
	test	bl,C_IMM8
	je	.check_if_lock_is_valid
	or	[.out.flags],F_IMM8
	movsb
    .check_if_lock_is_valid:
	test	[.out.prefix],PRE_LOCK
	je	.check_if_relative
	test	bl,C_MODRM
	je	.lock_error
	cmp	cl,3
	je	.lock_error
	mov	ecx,sizeof.lock_table_0F
	lea	edi,[.base+lock_table_0F]
	cmp	[.out.opcode],0Fh
	je	.search_for_opcode
	and	bh,0FEh
	mov	ecx,sizeof.lock_table
	lea	edi,[.base+lock_table]
      .search_for_opcode:
	cmp	[edi],bh
	lea	edi,[edi+2]
	loopnz	.search_for_opcode
	jnz	.lock_error
	mov	cl,[.out.modrm.reg]
	mov	al,[edi-1]
	inc	cl
	shr	al,cl
	jnc	.check_if_relative
      .lock_error:
	or	[.out.flags],F_ERROR_LOCK
    .check_if_relative:
	test	bl,C_REL
	je	.check_if_group
	or	[.out.flags],F_RELATIVE
    .check_if_group:
	test	bl,C_GROUP
	je	.fin
	or	[.out.flags],F_GROUP
    .fin:
	pop	eax
	xchg	eax,esi
	sub	eax,esi
	mov	[.out.len],al
	cmp	al,15
	jb	.15
	or	[.out.flags],F_ERROR_LENGTH
      .15:
	xor	eax,eax
	test	[.out.flags],F_ERROR_OPCODE+F_ERROR_LENGTH+F_ERROR_LOCK+F_VEX_BAD_PREFIX
	sete	al
	mov	[esp+1Ch],eax
	popad
	retn

  ; opcode table flags

  C_NONE	      = 000h
  C_MODRM	      = 001h
  C_IMM8	      = 002h
  C_IMM16	      = 004h
  C_IMM32	      = 008h
  C_REL 	      = 010h
  C_GROUP	      = 020h
  ; special encodings
  C_MOFFS	      = 0FBh
  C_PREFIX	      = 0FCh
  C_0F		      = 0FDh
  C_3BYTE	      = 0FEh
  C_UNDEFINED	      = 0FFh

  ; flags table indices

  T_NONE	      = 0
  T_MODRM	      = 1
  T_MODRM_IMM8	      = 2
  T_MODRM_IMM32       = 3
  T_IMM8	      = 4
  T_IMM16	      = 5
  T_IMM16_IMM8	      = 6
  T_IMM32	      = 7
  T_IMM32_IMM16       = 8
  T_REL_IMM8	      = 9
  T_REL_IMM32	      = 10
  T_GROUP_MODRM       = 11
  T_GROUP_MODRM_IMM8  = 12
  T_GROUP_MODRM_IMM32 = 13
  T_MOFFS	      = 14
  T_PREFIX	      = 15
  T_0F		      = 16
  T_3BYTE	      = 17
  T_UNDEFINED	      = 18

  ; flags table for grouping

flags_table:

	db	C_NONE
	db	C_MODRM
	db	C_MODRM+C_IMM8
	db	C_MODRM+C_IMM32
	db	C_IMM8
	db	C_IMM16
	db	C_IMM16+C_IMM8
	db	C_IMM32
	db	C_IMM32+C_IMM16
	db	C_REL+C_IMM8
	db	C_REL+C_IMM32
	db	C_GROUP+C_MODRM
	db	C_GROUP+C_MODRM+C_IMM8
	db	C_GROUP+C_MODRM+C_IMM32
	db	C_MOFFS
	db	C_PREFIX
	db	C_0F
	db	C_3BYTE
	db	C_UNDEFINED

  ; opcode table obviously (96 bytes)

opcode_table:

	db T_MODRM	      + 3 shl 5 ; 00-03
	db T_IMM8	      + 0 shl 5 ; 04
	db T_IMM32	      + 0 shl 5 ; 05
	db T_NONE	      + 1 shl 5 ; 06-07
	db T_MODRM	      + 3 shl 5 ; 08-0B
	db T_IMM8	      + 0 shl 5 ; 0C
	db T_IMM32	      + 0 shl 5 ; 0D
	db T_NONE	      + 0 shl 5 ; 0E
	db T_0F 	      + 0 shl 5 ; 0F
	db T_MODRM	      + 3 shl 5 ; 10-13
	db T_IMM8	      + 0 shl 5 ; 14
	db T_IMM32	      + 0 shl 5 ; 15
	db T_NONE	      + 1 shl 5 ; 16-17
	db T_MODRM	      + 3 shl 5 ; 18-1B
	db T_IMM8	      + 0 shl 5 ; 1C
	db T_IMM32	      + 0 shl 5 ; 1D
	db T_NONE	      + 1 shl 5 ; 1E-1F
	db T_MODRM	      + 3 shl 5 ; 20-23
	db T_IMM8	      + 0 shl 5 ; 24
	db T_IMM32	      + 0 shl 5 ; 25
	db T_PREFIX	      + 0 shl 5 ; 26
	db T_NONE	      + 0 shl 5 ; 27
	db T_MODRM	      + 3 shl 5 ; 28-2B
	db T_IMM8	      + 0 shl 5 ; 2C
	db T_IMM32	      + 0 shl 5 ; 2D
	db T_PREFIX	      + 0 shl 5 ; 2E
	db T_NONE	      + 0 shl 5 ; 2F
	db T_MODRM	      + 3 shl 5 ; 30-33
	db T_IMM8	      + 0 shl 5 ; 34
	db T_IMM32	      + 0 shl 5 ; 35
	db T_PREFIX	      + 0 shl 5 ; 36
	db T_NONE	      + 0 shl 5 ; 37
	db T_MODRM	      + 3 shl 5 ; 38-3B
	db T_IMM8	      + 0 shl 5 ; 3C
	db T_IMM32	      + 0 shl 5 ; 3D
	db T_PREFIX	      + 0 shl 5 ; 3E
	db T_NONE	      + 7 shl 5 ; 3F-46
	db T_NONE	      + 7 shl 5 ; 47-4E
	db T_NONE	      + 7 shl 5 ; 4F-56
	db T_NONE	      + 7 shl 5 ; 57-5E
	db T_NONE	      + 2 shl 5 ; 5F-61
	db T_MODRM	      + 1 shl 5 ; 62-63
	db T_PREFIX	      + 3 shl 5 ; 64-67
	db T_IMM32	      + 0 shl 5 ; 68
	db T_MODRM_IMM32      + 0 shl 5 ; 69
	db T_IMM8	      + 0 shl 5 ; 6A
	db T_MODRM_IMM8       + 0 shl 5 ; 6B
	db T_NONE	      + 3 shl 5 ; 6C-6F
	db T_REL_IMM8	      + 7 shl 5 ; 70-77
	db T_REL_IMM8	      + 7 shl 5 ; 78-7F
	db T_GROUP_MODRM_IMM8 + 0 shl 5 ; 80
	db T_GROUP_MODRM_IMM32+ 0 shl 5 ; 81
	db T_GROUP_MODRM_IMM8 + 1 shl 5 ; 82-83
	db T_MODRM	      + 7 shl 5 ; 84-8B
	db T_MODRM	      + 3 shl 5 ; 8C-8F
	db T_NONE	      + 7 shl 5 ; 90-97
	db T_NONE	      + 1 shl 5 ; 98-99
	db T_IMM32_IMM16      + 0 shl 5 ; 9A
	db T_NONE	      + 4 shl 5 ; 9B-9F
	db T_MOFFS	      + 3 shl 5 ; A0-A3
	db T_NONE	      + 3 shl 5 ; A4-A7
	db T_IMM8	      + 0 shl 5 ; A8
	db T_IMM32	      + 0 shl 5 ; A9
	db T_NONE	      + 5 shl 5 ; AA-AF
	db T_IMM8	      + 7 shl 5 ; B0-B7
	db T_IMM32	      + 7 shl 5 ; B8-BF
	db T_GROUP_MODRM_IMM8 + 1 shl 5 ; C0-C1
	db T_IMM16	      + 0 shl 5 ; C2
	db T_NONE	      + 0 shl 5 ; C3
	db T_MODRM	      + 1 shl 5 ; C4-C5
	db T_MODRM_IMM8       + 0 shl 5 ; C6
	db T_MODRM_IMM32      + 0 shl 5 ; C7
	db T_IMM16_IMM8       + 0 shl 5 ; C8
	db T_NONE	      + 0 shl 5 ; C9
	db T_IMM16	      + 0 shl 5 ; CA
	db T_NONE	      + 1 shl 5 ; CB-CC
	db T_IMM8	      + 0 shl 5 ; CD
	db T_NONE	      + 1 shl 5 ; CE-CF
	db T_GROUP_MODRM      + 3 shl 5 ; D0-D3
	db T_IMM8	      + 1 shl 5 ; D4-D5
	db T_NONE	      + 1 shl 5 ; D6-D7
	db T_GROUP_MODRM      + 7 shl 5 ; D8-DF
	db T_REL_IMM8	      + 3 shl 5 ; E0-E3
	db T_IMM8	      + 3 shl 5 ; E4-E7
	db T_REL_IMM32	      + 1 shl 5 ; E8-E9
	db T_IMM32_IMM16      + 0 shl 5 ; EA
	db T_REL_IMM8	      + 0 shl 5 ; EB
	db T_NONE	      + 3 shl 5 ; EC-EF
	db T_PREFIX	      + 0 shl 5 ; F0
	db T_NONE	      + 0 shl 5 ; F1
	db T_PREFIX	      + 1 shl 5 ; F2-F3
	db T_NONE	      + 1 shl 5 ; F4-F5
	db T_GROUP_MODRM_IMM8 + 0 shl 5 ; F6
	db T_GROUP_MODRM_IMM32+ 0 shl 5 ; F7
	db T_NONE	      + 5 shl 5 ; F8-FD
	db T_GROUP_MODRM      + 1 shl 5 ; FE-FF

  ; escaped opcode table (66 bytes)

opcode_table_0F:

	db T_GROUP_MODRM      + 1 shl 5 ; 00-01
	db T_MODRM	      + 1 shl 5 ; 02-03
	db T_UNDEFINED	      + 0 shl 5 ; 04
	db T_NONE	      + 4 shl 5 ; 05-09
	db T_UNDEFINED	      + 0 shl 5 ; 0A
	db T_NONE	      + 0 shl 5 ; 0B
	db T_UNDEFINED	      + 0 shl 5 ; 0C
	db T_GROUP_MODRM      + 0 shl 5 ; 0D
	db T_NONE	      + 0 shl 5 ; 0E
	db T_MODRM_IMM8       + 0 shl 5 ; 0F
	db T_MODRM	      + 7 shl 5 ; 10-17
	db T_NONE	      + 0 shl 5 ; 18
	db T_MODRM	      + 7 shl 5 ; 19-20
	db T_MODRM	      + 2 shl 5 ; 21-23
	db T_UNDEFINED	      + 3 shl 5 ; 24-27
	db T_MODRM	      + 7 shl 5 ; 28-2F
	db T_NONE	      + 5 shl 5 ; 30-35
	db T_UNDEFINED	      + 0 shl 5 ; 36
	db T_NONE	      + 0 shl 5 ; 37
	db T_3BYTE	      + 0 shl 5 ; 38
	db T_UNDEFINED	      + 0 shl 5 ; 39
	db T_3BYTE	      + 0 shl 5 ; 3A
	db T_UNDEFINED	      + 4 shl 5 ; 3B-3F
	db T_MODRM	      + 7 shl 5 ; 40-47
	db T_MODRM	      + 7 shl 5 ; 48-4F
	db T_MODRM	      + 7 shl 5 ; 50-57
	db T_MODRM	      + 7 shl 5 ; 58-5F
	db T_MODRM	      + 7 shl 5 ; 60-67
	db T_MODRM	      + 7 shl 5 ; 68-6F
	db T_MODRM_IMM8       + 0 shl 5 ; 70
	db T_GROUP_MODRM_IMM8 + 2 shl 5 ; 71-73
	db T_MODRM	      + 2 shl 5 ; 74-76
	db T_NONE	      + 0 shl 5 ; 77
	db T_MODRM	      + 1 shl 5 ; 78-79
	db T_UNDEFINED	      + 1 shl 5 ; 7A-7B
	db T_MODRM	      + 3 shl 5 ; 7C-7F
	db T_REL_IMM32	      + 7 shl 5 ; 80-87
	db T_REL_IMM32	      + 7 shl 5 ; 88-8F
	db T_MODRM	      + 7 shl 5 ; 90-97
	db T_MODRM	      + 7 shl 5 ; 98-9F
	db T_NONE	      + 2 shl 5 ; A0-A2
	db T_MODRM	      + 0 shl 5 ; A3
	db T_MODRM_IMM8       + 0 shl 5 ; A4
	db T_MODRM	      + 0 shl 5 ; A5
	db T_UNDEFINED	      + 1 shl 5 ; A6-A7
	db T_NONE	      + 2 shl 5 ; A8-AA
	db T_MODRM	      + 0 shl 5 ; AB
	db T_MODRM_IMM8       + 0 shl 5 ; AC
	db T_MODRM	      + 0 shl 5 ; AD
	db T_GROUP_MODRM      + 0 shl 5 ; AE
	db T_MODRM	      + 7 shl 5 ; AF-B6
	db T_MODRM	      + 2 shl 5 ; B7-B9
	db T_GROUP_MODRM_IMM8 + 0 shl 5 ; BA
	db T_MODRM	      + 6 shl 5 ; BB-C1
	db T_MODRM_IMM8       + 0 shl 5 ; C2
	db T_MODRM	      + 0 shl 5 ; C3
	db T_MODRM_IMM8       + 2 shl 5 ; C4-C6
	db T_GROUP_MODRM      + 0 shl 5 ; C7
	db T_NONE	      + 7 shl 5 ; C8-CF
	db T_MODRM	      + 7 shl 5 ; D0-D7
	db T_MODRM	      + 7 shl 5 ; D8-DF
	db T_MODRM	      + 7 shl 5 ; E0-E7
	db T_MODRM	      + 7 shl 5 ; E8-EF
	db T_MODRM	      + 7 shl 5 ; F0-F7
	db T_MODRM	      + 6 shl 5 ; F8-FE
	db T_NONE	      + 0 shl 5 ; FF

  ; 3-byte opcode table for 0F 38

opcode_table_0F_38:			; C_MODRM

	db	000h, 001h, 002h, 003h
	db	004h, 005h, 006h, 007h
	db	008h, 009h, 00Ah, 00Bh
	db	010h, 014h, 015h, 017h
	db	01Ch, 01Dh, 01Eh, 020h
	db	021h, 022h, 023h, 024h
	db	025h, 028h, 029h, 02Ah
	db	02Bh, 030h, 031h, 032h
	db	033h, 034h, 035h, 037h
	db	038h, 039h, 03Ah, 03Bh
	db	03Ch, 03Dh, 03Eh, 03Fh
	db	040h, 041h, 080h, 081h
	db	082h, 0DBh, 0DCh, 0DDh
	db	0DEh, 0DFh, 0F0h, 0F1h

sizeof.opcode_table_0F_38 = $-opcode_table_0F_38

	db	00Ch, 00Dh, 00Eh, 00Fh
	db	018h, 019h, 01Ah, 02Ch
	db	02Dh, 02Eh, 02Fh

sizeof.opcode_table_0F_38_V = $-opcode_table_0F_38

  ; 3-byte opcode table for 0F 3A

opcode_table_0F_3A:			; C_MODRM+C_IMM8

	db	008h, 009h, 00Ah, 00Bh
	db	00Ch, 00Dh, 00Eh, 00Fh
	db	014h, 015h, 016h, 017h
	db	020h, 021h, 022h, 040h
	db	041h, 042h, 044h, 060h
	db	061h, 062h, 063h, 0DFh

sizeof.opcode_table_0F_3A = $-opcode_table_0F_3A

	db	004h, 005h, 006h, 018h
	db	019h, 04Ah, 04Bh, 04Ch

sizeof.opcode_table_0F_3A_V = $-opcode_table_0F_3A

  ; opcodes with possible LOCK-prefix

lock_table:

	db	000h, 0 		; add
	db	008h, 0 		; or
	db	010h, 0 		; adc
	db	018h, 0 		; sbb
	db	020h, 0 		; and
	db	028h, 0 		; sub
	db	030h, 0 		; xor
	db	080h, 10000000b 	; add|or|adc|sbb|and|sub|xor reg=0-6
	db	082h, 10000000b 	; ^
	db	086h, 0 		; xchg
	db	0F6h, 11110011b 	; not|neg reg=2|3
	db	0FEh, 11111100b 	; inc|dec reg=0|1

sizeof.lock_table = $-lock_table

  ; escaped opcodes with possible LOCK-prefix

lock_table_0F:

	db	0ABh, 0 		; bts
	db	0B0h, 0 		; cmpxchg
	db	0B1h, 0 		; ^
	db	0B3h, 0 		; btr
	db	0BAh, 00011111b 	; bts|btr|btc reg=5-7
	db	0BBh, 0 		; btc
	db	0C0h, 0 		; xadd
	db	0C1h, 0 		; ^
	db	0C7h, 11111101b 	; cmpxchg16b|cmpxchg8b reg=1

sizeof.lock_table_0F = $-lock_table_0F

endp
